package com.cherrypt.api.core.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cherrypt.api.common.enums.ResultEnum;
import com.cherrypt.api.common.exception.TipException;
import com.cherrypt.api.core.dao.SignRecordDao;
import com.cherrypt.api.model.dataobject.SignRecord;
import com.cherrypt.api.model.dto.SignRecordDto;
import com.cherrypt.api.core.service.SignRecordService;
import com.cherrypt.api.core.service.UserInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Calendar;

/**
 * @author intent
 * @date 2019/7/22 11:27
 * @about <link href='http://zzyitj.xyz/'/>
 */
@Service
public class SignRecordServiceImpl extends ServiceImpl<SignRecordDao, SignRecord> implements SignRecordService {
    @Autowired
    private UserInfoService userInfoService;

    // 签到获得的初始经验值
    public static final int INIT_EXP = 3;

    /**
     * 签到流程
     * 1. 判断数据库中有没有uid当前月份的签到数据，没有就插入新数据，有执行第2步
     * 2. 令day为当月的第几天，判断mask & (1 << day)大于0，说明今天已经签到了抛出异常，如果为0，说明今天未签到，执行第3步
     * 3. 获取今天是当月的第几天，如果是第1天那直接插入新数据，如果不是执行第4步
     * 4. 判断mask & (1 << (day - 1))大于0，说明day - 1签到了，如果为0，说明day - 1未签到，执行第5步
     * 5. 如果day - 1签到了则把continue_sign_month字段+1 更新mask=mask | (1 << day)
     * 更多请查看<link>https://blog.csdn.net/liyunlong41/article/details/86739134</link>
     */
    @Override
    public SignRecordDto signed(int uid) throws TipException {
        String dateMonth = getDateMonth();
        int day = Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
        SignRecord signRecord = this.getOne(new QueryWrapper<SignRecord>()
                .eq("date_month", dateMonth)
                .eq("uid", uid));
        if (signRecord == null) {
            if (saveSignRecord(uid, dateMonth, day)) {
                // 经验加3，告辞
                return signedUtil(uid, 1);
            } else {
                // 签到错误
                throw new TipException(ResultEnum.SIGN_RECORD_ERROR);
            }
        }
        // 判断今天是否签到
        boolean isSignRecord = (signRecord.getMask() & (1L << day)) > 0;
        if (isSignRecord) {
            // 说明已经签到了
            throw new TipException(ResultEnum.SIGN_RECORD_ERROR);
        }
        // 今天没签到但今天是这个月的第一天，直接插入
        if (day == 1) {
            if (saveSignRecord(uid, dateMonth, 1)) {
                // 经验加3，告辞
                return signedUtil(uid, 1);
            } else {
                // 签到错误
                throw new TipException(ResultEnum.SIGN_RECORD_ERROR);
            }
        }
        SignRecord nowSignRecord = new SignRecord();
        nowSignRecord.setMask(signRecord.getMask() | (1L << day));
        // 判断是前一天是否签到
        boolean isOldSignRecord = (signRecord.getMask() & (1L << (day - 1))) > 0;
        if (isOldSignRecord) {
            // 如果前一天签到了，那就把continue_sign_month字段+1
            nowSignRecord.setContinueSignMonth(signRecord.getContinueSignMonth() + 1);
        } else {
            nowSignRecord.setContinueSignMonth(1);
        }
        if (updateSignRecord(uid, nowSignRecord)) {
            return signedUtil(uid, nowSignRecord.getContinueSignMonth());
        } else {
            // 签到错误
            throw new TipException(ResultEnum.SIGN_RECORD_ERROR);
        }
    }

    @Override
    public boolean isSigned(int uid) {
        String dateMonth = getDateMonth();
        int day = Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
        SignRecord signRecord = this.getOne(new QueryWrapper<SignRecord>()
                .eq("date_month", dateMonth)
                .eq("uid", uid));
        if (signRecord == null) {
            return false;
        } else {
            // 判断今天是否签到
            return (signRecord.getMask() & (1 << day)) > 0;
        }
    }

    private String getDateMonth() {
        int year = Calendar.getInstance().get(Calendar.YEAR);
        int month = Calendar.getInstance().get(Calendar.MONTH) + 1;
        return year + "-" + (month < 10 ? "0" + month : month);
    }

    private SignRecordDto signedUtil(int uid, int continueSignMonth) throws TipException {
        // 签到增加exp规则：连续签到天数 * 3
        long exp = continueSignMonth * INIT_EXP;
        // 经验加3，告辞
        userInfoService.updateExpByUid(uid, INIT_EXP);
        SignRecordDto signRecordDTO = new SignRecordDto();
        signRecordDTO.setContinueSignMonth(continueSignMonth);
        signRecordDTO.setExp(exp);
        return signRecordDTO;
    }

    @Override
    public boolean saveSignRecord(int uid, String dateMonth, int day) {
        SignRecord signRecord = new SignRecord();
        signRecord.setUid(uid);
        signRecord.setDateMonth(dateMonth);
        signRecord.setMask(1L << day);
        signRecord.setContinueSignMonth(1);
        return this.save(signRecord);
    }

    @Override
    public boolean updateSignRecord(int uid, SignRecord signRecord) {
        String dateMonth = getDateMonth();
        return this.update(signRecord, new UpdateWrapper<SignRecord>()
                .eq("date_month", dateMonth)
                .eq("uid", uid));
    }
}
